package com.vlyman.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.sql.SQLException;

/**
 * 类描述：
 *  druid数据源配置类
 * @author chenjs
 * @date 2018/9/15
 */
@Slf4j
@Configuration
public class DruidConfig {

    @Value("${spring.datasource.url}")
    private String dbUrl;
    @Value("${spring.datasource.username}")
    private String username;
    @Value("${spring.datasource.password}")
    private String password;
    @Value("${spring.datasource.driver-class-name}")
    private String driverClassName;
    /**
     * @Description 初始化连接池连接数，默认值：10
     */
    @Value("${spring.datasource.initialSize:10}")
    private int initialSize;

    /**
     * @Description 连接池最小连接数，默认值：10
     */
    @Value("${spring.datasource.minIdle:10}")
    private int minIdle;

    /**
     * @Description 连接池最大连接数，默认值：30
     */
    @Value("${spring.datasource.maxActive:30}")
    private int maxActive;

    /**
     * @Description 配置获取连接等待超时的时间，默认值：60000
     */
    @Value("${spring.datasource.maxWait:60000}")
    private int maxWait;

    /**
     * @Description 配置间隔多久才进行一次检测，检测需要关闭的空闲连接，单位是毫秒，默认值：30000
     */
    @Value("${spring.datasource.timeBetweenEvictionRunsMillis:30000}")
    private int timeBetweenEvictionRunsMillis;

    /**
     * @Description 配置一个连接在池中最小生存的时间，单位是毫秒，默认值：300000
     */
    @Value("${spring.datasource.minEvictableIdleTimeMillis:300000}")
    private int minEvictableIdleTimeMillis;
    @Value("${spring.datasource.validationQuery:SELECT 1 FROM DUAL}")
    private String validationQuery;
    @Value("${spring.datasource.testWhileIdle:true}")
    private boolean testWhileIdle;
    @Value("${spring.datasource.testOnBorrow:false}")
    private boolean testOnBorrow;
    @Value("${spring.datasource.testOnReturn:false}")
    private boolean testOnReturn;
    @Value("${spring.datasource.poolPreparedStatements:true}")
    private boolean poolPreparedStatements;
    @Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize:20}")
    private int maxPoolPreparedStatementPerConnectionSize;

    /**
     * @Description 别名的方式配置扩展插件，常用的插件有：
        监控统计stat
        日志log4j
        防御sql注入wall
     */
    @Value("${spring.datasource.filters:stat,wall,slf4j}")
    private String filters;

    /**
     * @Description 物理连接初始化的时候执行的sql，默认值：SELECT 1
     */
    @Value("${spring.datasource.initSqls:[\"SELECT 1;\"]}")
    private String initSqls;

    /**
     * druid监控页面，登录IP白名单(多个使用,隔开)
     */
    @Value("${druid.stat.allow:}")
    private String statAllow;

    /**
     * druid监控页面，登录黑名单(多个使用,隔开)
     */
    @Value("${druid.stat.deny:}")
    private String statDeny;

    /**
     * druid监控登录名，默认值：vlyman
     */
    @Value("${druid.stat.login-user:vlyman}")
    private String statLoginUser;

    /**
     * druid监控登录密码，默认值：vlyman@admin
     */
    @Value("${druid.stat.login-password:vlyman@admin}")
    private String statLoginPassword;

    /**
     * 方法描述：
     * druid数据源配置方法
     *
     * @return DataSource
     * @author chenjs
     * @date 2018/9/15
     */
    @Bean
    @Primary
    public DataSource dataSource() {
        log.info("初始化Druid数据源");
        DruidDataSource datasource = new DruidDataSource();
        datasource.setUrl(this.dbUrl);
        datasource.setUsername(username);
        datasource.setPassword(password);
        datasource.setDriverClassName(driverClassName);

        //configuration
        datasource.setInitialSize(initialSize);
        datasource.setMinIdle(minIdle);
        datasource.setMaxActive(maxActive);
        datasource.setMaxWait(maxWait);
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        datasource.setValidationQuery(validationQuery);
        datasource.setTestWhileIdle(testWhileIdle);
        datasource.setTestOnBorrow(testOnBorrow);
        datasource.setTestOnReturn(testOnReturn);
        datasource.setPoolPreparedStatements(poolPreparedStatements);
        datasource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
        datasource.setConnectionInitSqls(JSONObject.parseArray(initSqls, String.class));
        try {
            datasource.setFilters(filters);
        } catch (SQLException e) {
            log.error("druid数据源初始化filter失败: " + e);
        }
        return datasource;
    }

    @Bean
    public ServletRegistrationBean druidServlet() {
        log.info("初始化Druid监控Servlet配置");
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
        if (StringUtils.hasText(statAllow)) {
            // IP白名单
            servletRegistrationBean.addInitParameter("allow", statAllow);
        }
        if (StringUtils.hasText(statDeny)) {
            // IP黑名单(共同存在时，deny优先于allow)
            servletRegistrationBean.addInitParameter("deny", statDeny);
        }
        //控制台管理用户
        servletRegistrationBean.addInitParameter("loginUsername", statLoginUser);
        servletRegistrationBean.addInitParameter("loginPassword", statLoginPassword);
        //是否能够重置数据 禁用HTML页面上的“Reset All”功能
        servletRegistrationBean.addInitParameter("resetEnable", "false");
        // 禁用Druid session监控
        servletRegistrationBean.addInitParameter("sessionStatEnable", "false");
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean filterRegistrationBean() {
        FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new WebStatFilter());
        filterRegistrationBean.addUrlPatterns("/*");
        filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
        return filterRegistrationBean;
    }
}
